<?php
/**
 * Http请求客户端
 * 
 * <code>
 *  $http = new IHttpClient("http://my/test/response/index?a=b");
 *	$http->setBody("a=b&c=d&e=f");
 *	$http->setContentType("application/x-www-form-urlencoded");
 *	$response = $http->request(IHttpClient::POST_METHOD);
 *	print_r($response->getBody());
 *	</code>
 * 
 * 结果可能是：
 * <code>
 * Array
 * (
 *     [a] => b
 *     [c] => d
 *     [e] => f
 * )
 * 
 * </code>
 *
 * @version $Id: IHttpClient.php 312 2008-04-23 16:29:38Z iwind $
 * @package util.net
 * @since 0.0.3
 */
class IHttpClient extends IObject {
	private $headers = array();
	private $persist;
	private $body;
	const GET_METHOD = "GET";
	const POST_METHOD = "POST";
	/**
	 * Enter description here...
	 *
	 * @var IURI
	 */
	private $uri;
	private $timeout = 30;
	private static $connection;
	
	/**
	 * 构造器
	 *
	 * @param string $uri 目标URI
	 * @since 0.0.3
	 */
	public function __construct($uri) {
		$this->uri = new IURI($uri);
		if (!isset($this->headers["Host"])) {
			$this->addHeader("Host", $this->uri->getHost());
		}
	}
	
	/**
	 * 设置发送的主体
	 *
	 * @param string $body 主体
	 * @since 0.0.3
	 */
	public function setBody($body) {
		$this->body = $body;
	}
	
	/**
	 * 设置发送的内容类型
	 *
	 * 比如
	 * - post: application/x-www-form-urlencoded
	 * - xml: text/xml;charset=UTF-8
	 * - ...
	 * 
	 * @param string $contentType 内容类型
	 * @since 0.0.3
	 */
	public function setContentType($contentType) {
		$this->headers["Content-Type"] = $contentType;
	}
	
	/**
	 * 设置是否持久连接
	 * 
	 * IHttpClinet不能处理持久连接
	 *
	 * @param boolean $persist 是否持久连接
	 * @since 0.0.3
	 */
	public function setPersist($persist) {
		$this->persist = $persist;
	}
	
	/**
	 * 添加Header报头
	 *
	 * @param string $name 名称
	 * @param string|integer $value 值
	 * @since 0.0.3
	 */
	public function addHeader($name, $value) {
		$this->headers[$name] = $value;
	}
	
	/**
	 * 设置Header报头
	 *
	 * @param array $headers 一组报头
	 * @since 0.0.3
	 * @see addHeader
	 */
	public function setHeaders(array $headers) {
		$this->headers = $headers;
	}
	
	/**
	 * 设置连接超时时间
	 *
	 * @param integer $timeout 超时时间
	 * @since 0.0.3
	 */
	public function setTimeout($timeout) {
		$this->timeout = intval($timeout);
	}
	
	/**
	 * 发送请求
	 *
	 * @param string $method 请求方法
	 * @param string $httpVersion HTTP版本号
	 * @return IHttpResponse
	 * @since 0.0.3
	 */
	public function request($method = IHttpClient::GET_METHOD, $httpVersion = "1.1") {
		$errorNo = null;
		$errorString = null;
		if (!$this->persist) {
			$connection = fsockopen( $this->uri->getHost(), $this->uri->getPort(), $errorNo, $errorString, $this->timeout);
		}
		else {
			if (self::$connection === null) {
				self::$connection = pfsockopen( $this->uri->getHost(), $this->uri->getPort(), $errorNo, $errorString, $this->timeout);
			}
			$connection = &self::$connection;
		}
		if (!$connection) {
			throw new INetException("http client open failed");
		}
		
		$out = "{$method} " .  $this->uri->getPath() . (( $this->uri->getQuery() !== null)?"?" .  $this->uri->getQuery():"") . " HTTP/{$httpVersion}\r\n";
		foreach ($this->headers as $name=>$value) {
			$out .= "{$name}: {$value}\r\n";
		}
		if ($this->body !== null) {
			$body = rawurldecode($this->body);
			$out .= "Content-Length: " . strlen($body) . "\r\n";
		}	
		$out .= "Connection: Close\r\n\r\n";
		if ($this->body !== null) {
			$body = rawurldecode($this->body);
			$out .= $body . "\r\n";
		}
		fwrite($connection, $out);
		
		$responseString = "";
		while (!feof($connection)) {
			$line = fgets($connection);
			$responseString .= $line;
		}
		
		if (!$this->persist) {
			fclose($connection);
		}
		
		if ($responseString == null) {
			throw new INetException("http response string is null");
		}
		
		return new IHttpResponse($responseString);
	}
}

?>